package com.lanhao.aot.elasticsearch;

import java.util.List;

import org.apache.commons.lang3.tuple.Pair;

import com.aliyun.openservices.shade.org.apache.commons.lang3.StringUtils;
import com.google.common.collect.Lists;

import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import co.elastic.clients.elasticsearch._types.query_dsl.Operator;
import co.elastic.clients.elasticsearch._types.query_dsl.TextQueryType;

/**
 * Elasticsearch中search查询的请求参数封装类
 * 
 * @author kunzhou3
 * @since 2022-07-18
 */
public class SearchReqParamDTO {
	/**
	 * 索引名称
	 */
	private String indexName;
	/**
	 * 分页信息：Key-页码 | Value-展示条数
	 */
	private Pair<Integer, Integer> pagination;
	/**
	 * 排序字段信息集合：Key-字段名称 | Value-排序方式
	 */
	private List<Pair<String, String>> sortFields;

	/**
	 * 查询时返回结果包含 OR 过滤的字段集合
	 */
	private List<String> includes;
	private List<String> excludes;
	private Pair<String, Aggregation> aggregations;
	
	/**
	 * 搜索模式
	 */
	private SearchMode searchMode;
	
	/**
	 * 非bool查询时的field
	 */
	private List<String> fieldList;
	
	/**
	 * 查询内容值
	 */
	private List<String> valueList;
	
	/**
	 * slop (default 0)：（slop：溢出）来指定额外加几个单词也可以命中。
	 */
	private Integer slop;
	
	private Object rangeStart;
	private Object rangeEnd;
	private Integer rangeType; // 0 双闭合  1 左开右闭  2 左闭右开  3双开
	
	/**
	   * 定义最初始不会被“模糊”的term的数量。
	   * 这是基于用户的输入一般不会在最开始犯错误的设定的基础上设置的参数。
	   * 这个参数的设定将减少去召回限定编辑距离的的term时，检索的term的数量。
	   * 默认参数为0.
	 */
	private Integer prefixLength;
	/**
	  * 定义最大的编辑距离，默认为AUTO，即按照es的默认配置，fuzziness可选的值为0,1,2，也就是说编辑距离最大只能设置为2.
	 * AUTO策略：在AUTO模式下，es将根据输入查询的term的长度决定编辑距离大小。用户也可以自定义term长度边界的最大和最小值，AUTO:[low],[high]，如果没有定义的话，默认值为3和6，即等价于 AUTO:3,6，即按照以下方案：
	  *  输入查询term的长度：0-2 : 必须精确匹配    3-5 : 编辑距离为1  | >5 : 编辑距离为2
	 */
	private String fuzziness;
	
	/**
	 * 三种： best_fields 、 most_fields 和 cross_fields （最佳字段、多数字段、跨字段）。默认情况下，查询的类型是 best_fields
	 * best_fields是取子查询中算分最高的作为最终算分
	 * most_fields则是取子查询算分的和作为最终算分，我们也可以理解按照关键字出现的次数来算，出现的越多，算分越高
	 */
	private TextQueryType textQueryType;
	
	/**
	 *  And | OR
	 */
	private Operator operator;
	
	/**
	 * bool查询时的参数集合信息
	 */
	private List<BoolQueryParamDTO> boolQueryParamList;

	public SearchReqParamDTO() {

	}
	
	public SearchReqParamDTO(String indexName, SearchMode searchMode) {
		this.indexName = indexName;
		this.searchMode = searchMode;
	}
	
	public SearchReqParamDTO(String indexName, SearchMode searchMode, String field, String queryValue) {
		this.indexName = indexName;
		this.searchMode = searchMode;
		this.fieldList = Lists.newArrayList(field);
		this.valueList = Lists.newArrayList(queryValue);
	}
	
	public SearchReqParamDTO(String indexName, SearchMode searchMode, Integer rangeType, Object rangeStart, Object rangeEnd) {
		this.indexName = indexName;
		this.searchMode = searchMode;
		this.rangeType = rangeType;
		this.rangeStart = rangeStart;
		this.rangeEnd = rangeEnd;
	}
	
	public SearchReqParamDTO(String indexName, SearchMode searchMode, List<String> fieldList, String queryValue) {
		this.indexName = indexName;
		this.searchMode = searchMode;
		this.fieldList = fieldList;
		this.valueList = Lists.newArrayList(queryValue);
	}
	
	public SearchReqParamDTO(String indexName, SearchMode searchMode, String field, List<String> valueList) {
		this.indexName = indexName;
		this.searchMode = searchMode;
		this.fieldList = Lists.newArrayList(field);
		this.valueList = valueList;
	}

	public SearchReqParamDTO(String indexName, SearchMode searchMode, Pair<Integer, Integer> pagination) {
		this.indexName = indexName;
		this.searchMode = searchMode;
		this.pagination = pagination;
	}

	public SearchReqParamDTO(String indexName, SearchMode searchMode, Pair<Integer, Integer> pagination,
			List<Pair<String, String>> sortFields) {
		this.indexName = indexName;
		this.searchMode = searchMode;
		this.pagination = pagination;
		this.sortFields = sortFields;
	}

	public SearchReqParamDTO(String indexName, SearchMode searchMode, List<BoolQueryParamDTO> boolQueryParamList) {
		this.indexName = indexName;
		this.searchMode = searchMode;
		this.boolQueryParamList = boolQueryParamList;
	}

	public String getIndexName() {
		return indexName;
	}

	public void setIndexName(String indexName) {
		this.indexName = indexName;
	}

	public Pair<Integer, Integer> getPagination() {
		return pagination;
	}

	public void setPagination(Pair<Integer, Integer> pagination) {
		this.pagination = pagination;
	}

	public List<Pair<String, String>> getSortFields() {
		return sortFields;
	}

	public void setSortFields(List<Pair<String, String>> sortFields) {
		this.sortFields = sortFields;
	}

	public List<String> getIncludes() {
		return includes;
	}

	public void setIncludes(List<String> includes) {
		this.includes = includes;
	}

	public List<String> getExcludes() {
		return excludes;
	}

	public void setExcludes(List<String> excludes) {
		this.excludes = excludes;
	}
	
	public Pair<String, Aggregation> getAggregations() {
		return aggregations;
	}

	public void setAggregations(Pair<String, Aggregation> aggregations) {
		this.aggregations = aggregations;
	}

	public SearchMode getSearchMode() {
		return searchMode;
	}

	public void setSearchMode(SearchMode searchMode) {
		this.searchMode = searchMode;
	}

	public List<String> getFieldList() {
		return fieldList;
	}

	public void setFieldList(List<String> fieldList) {
		this.fieldList = fieldList;
	}

	public List<String> getValueList() {
		return valueList;
	}

	public void setValueList(List<String> valueList) {
		this.valueList = valueList;
	}

	public Object getRangeStart() {
		return rangeStart;
	}

	public void setRangeStart(Object rangeStart) {
		this.rangeStart = rangeStart;
	}

	public Object getRangeEnd() {
		return rangeEnd;
	}

	public void setRangeEnd(Object rangeEnd) {
		this.rangeEnd = rangeEnd;
	}

	public Integer getRangeType() {
		return rangeType;
	}

	public void setRangeType(Integer rangeType) {
		this.rangeType = rangeType;
	}

	public Integer getSlop() {
		return slop;
	}

	public void setSlop(Integer slop) {
		this.slop = slop;
	}

	public Integer getPrefixLength() {
		return prefixLength;
	}

	public void setPrefixLength(Integer prefixLength) {
		this.prefixLength = prefixLength;
	}

	public String getFuzziness() {
		return fuzziness;
	}

	public void setFuzziness(String fuzziness) {
		this.fuzziness = fuzziness;
	}
	
	public TextQueryType getTextQueryType() {
		return textQueryType;
	}

	public void setTextQueryType(TextQueryType textQueryType) {
		this.textQueryType = textQueryType;
	}

	public Operator getOperator() {
		return operator;
	}

	public void setOperator(Operator operator) {
		this.operator = operator;
	}
	
	public List<BoolQueryParamDTO> getBoolQueryParamList() {
		return boolQueryParamList;
	}

	public void setBoolQueryParamList(List<BoolQueryParamDTO> boolQueryParamList) {
		this.boolQueryParamList = boolQueryParamList;
	}

	public static SearchReqParamDTO matchAllSearchParam(String indexName) {
		return new SearchReqParamDTO(indexName, SearchMode.MATCH_ALL);
	}
	
	public static SearchReqParamDTO matchSearchParam(String indexName, String field, String queryValue) {
		return new SearchReqParamDTO(indexName, SearchMode.MATCH, field, queryValue);
	}
	
	public static SearchReqParamDTO matchPhraseSearchParam(String indexName, String field, String queryValue) {
		return new SearchReqParamDTO(indexName, SearchMode.MATCH_PHRASE, field, queryValue);
	}
	
	public static SearchReqParamDTO matchPhrasePrefixSearchParam(String indexName, String field, String queryValue) {
		return new SearchReqParamDTO(indexName, SearchMode.MATCH_PHRASE_PREFIX, field, queryValue);
	}
	
	public static SearchReqParamDTO matchPhrasePrefixSearchParam(String indexName, String field, String queryValue, Integer slop) {
		SearchReqParamDTO searchReqParamDTO = new SearchReqParamDTO(indexName, SearchMode.MATCH_PHRASE_PREFIX, field, queryValue);
		searchReqParamDTO.setSlop(slop);
		return searchReqParamDTO;
	}
	
	public static SearchReqParamDTO multiMatchSearchParam(String indexName, List<String> fieldList, String queryValue) {
		return new SearchReqParamDTO(indexName, SearchMode.MULTI_MATCH, fieldList, queryValue);
	}
	
	public static SearchReqParamDTO rangeSearchParam(String indexName, Integer rangeType, Object rangeStart, Object rangeEnd) {
		return new SearchReqParamDTO(indexName, SearchMode.RANGE, rangeType, rangeStart, rangeEnd);
	}
	
	public static SearchReqParamDTO fuzzySearchParam(String indexName, String field, String queryValue) {
		return new SearchReqParamDTO(indexName, SearchMode.FUZZY, field, queryValue);
	}
	
	public static SearchReqParamDTO fuzzySearchParam(String indexName, String field, String queryValue, Integer prefixLength, String fuzziness) {
		SearchReqParamDTO searchReqParamDTO = new SearchReqParamDTO(indexName, SearchMode.FUZZY, field, queryValue);
		if(prefixLength != null) {
			searchReqParamDTO.setPrefixLength(prefixLength);
		}
		if(StringUtils.isNotBlank(fuzziness)) {
			searchReqParamDTO.setFuzziness(fuzziness);
		}
		return searchReqParamDTO;
	}
	
	public static SearchReqParamDTO termSearchParam(String indexName, String field, String queryValue) {
		return new SearchReqParamDTO(indexName, SearchMode.TERM, field, queryValue);
	}
	
	public static SearchReqParamDTO termsSearchParam(String indexName, String field, List<String> valueList) {
		return new SearchReqParamDTO(indexName, SearchMode.TERMS, field, valueList);
	}
	
	public static SearchReqParamDTO wildcardSearchParam(String indexName, String field, String queryValue) {
		return new SearchReqParamDTO(indexName, SearchMode.WILDCARD, field, queryValue);
	}
	
	public static SearchReqParamDTO boolSearchParam(String indexName, List<BoolQueryParamDTO> boolQueryParamList) {
		return new SearchReqParamDTO(indexName, SearchMode.BOOL, boolQueryParamList);
	}
	
	public static SearchReqParamDTO boolSearchParam(String indexName, BoolQueryParamDTO boolQueryParam) {
		return new SearchReqParamDTO(indexName, SearchMode.BOOL, Lists.newArrayList(boolQueryParam));
	}
	
}
